package org.example.liuy.handler;

import com.sun.net.httpserver.HttpExchange;
import com.sun.net.httpserver.HttpHandler;
import lombok.extern.slf4j.Slf4j;

import java.io.IOException;
import java.util.UUID;
import java.util.concurrent.ThreadLocalRandom;

/**
 * 请求日志处理器 - 责任链模式中的第一个处理器
 * 用于记录所有进入的HTTP请求
 */
@Slf4j
public class RequestLoggingHandler implements HttpHandler {
    private static final int REQUEST_ID_LENGTH = 8;
    private static final char[] ALPHANUMERIC = "0123456789abcdef".toCharArray();

    private final HttpHandler nextHandler;
    // 使用ThreadLocal避免多线程竞争
    private final ThreadLocal<char[]> requestIdBuffer = ThreadLocal.withInitial(() -> new char[REQUEST_ID_LENGTH]);

    public RequestLoggingHandler(HttpHandler nextHandler) {
        this.nextHandler = nextHandler;
    }

    @Override
    public void handle(HttpExchange exchange) throws IOException {
        long startTime = System.currentTimeMillis();
        // 使用更轻量级的ID生成方式
        String requestId = generateRequestId();
        String method = exchange.getRequestMethod();
        String path = exchange.getRequestURI().getPath();
        String query = exchange.getRequestURI().getQuery();
        String clientIp = getClientIp(exchange);

        // 只在INFO级别启用时才记录开始日志，避免不必要的字符串操作
        if (log.isInfoEnabled()) {
            StringBuilder sb = new StringBuilder(128);
            sb.append('[').append(requestId).append("] ")
                    .append(method).append(' ').append(path);

            if (query != null) {
                sb.append('?').append(query);
            }

            sb.append(" - Client: ").append(clientIp).append(" - Request started");
            log.info(sb.toString());
        }

        try {
            nextHandler.handle(exchange);

            long duration = System.currentTimeMillis() - startTime;
            int statusCode = exchange.getResponseCode();

            // 只在INFO级别启用时才记录完成日志
            if (log.isInfoEnabled()) {
                log.info("[{}] {} {} - Completed in {}ms with status {}",
                        requestId, method, path, duration, statusCode);
            }

        } catch (Exception e) {
            long duration = System.currentTimeMillis() - startTime;
            // 错误日志总是记录
            log.error("[{}] {} {} - Failed after {}ms: {}",
                    requestId, method, path, duration, e.getMessage(), e);
            throw e;
        }
    }

    /**
     * 生成轻量级请求ID
     * <p>
     * 优化说明：
     * 1. 使用ThreadLocalRandom避免同步开销
     * 2. 使用预分配的字符数组避免对象创建
     * 3. 使用十六进制字符减少随机数生成次数
     * </p>
     *
     * @return 8位十六进制字符串形式的请求ID
     */
    private String generateRequestId() {
        char[] buffer = requestIdBuffer.get();
        for (int i = 0; i < REQUEST_ID_LENGTH; i++) {
            buffer[i] = ALPHANUMERIC[ThreadLocalRandom.current().nextInt(ALPHANUMERIC.length)];
        }
        return new String(buffer);
    }

    /**
     * 获取客户端IP地址
     *
     * @param exchange HTTP交换对象
     * @return 客户端IP地址
     */
    private String getClientIp(HttpExchange exchange) {
        return exchange.getRemoteAddress().getAddress().getHostAddress();
    }
}

